#include <memory.h>
#include "lib.h"

#include "vphand.h"
#include "vpgame.h"
#include "vpconn.h"
#include "shue.h"
#include "vphand.h"
#include "vpguts.h"
#include "vpsaved.h"

enum GameStates
{
	VPGS_NOTSTARTED		= 0,
	VPGS_GAMESTARTED	= 1,
	VPGS_DBLUPPENDING	= 2,
	VPGS_DBLUPSTARTED	= 4,
	VPGS_GAMEOVER		= 8
};
//
// valid combinations of GameStates are:
//		VPGS_NOTSTARTED.........................neither vpoker or dbl up started
//		VPGS_GAMESTARTED........................vpoker has been dealt
//		VPGS_GAMESTARTED | VPGS_DBLUPPENDING....vpoker drawn, dblup available
//		VPGS_GAMESTARTED | VPGS_DBLUPSTARTED....vpoker drawn, dblup dealt
//		VPGS_GAMEOVER...........................both vpoker and dblup done
//

#define VPEVT_DBLUP_WON			0xfe
#define VPEVT_DBLUP_LOSER		0xfc
#define VPEVT_DBLUP_TIE			0xfd

#ifdef FORCEDSHOE
#define VP_SHUE_MIN_SIZE 7 // CSN-13015 - MHVPoker forced shue minimum size
#endif

VPGame::VPGame(VPConnection* conn, int32 bet, bool8 dblUpEnabled)
{
	this->conn = conn;
	this->bet = bet;
	this->dblUpEnabled = dblUpEnabled;
	this->dlbUpCapAmount = conn->getDoubleUpCapAmount();
	guts = VPGuts::getGuts(conn->getMachId(), conn->getPayTableFreq());

	sgi.gameId = GAMEID;
	sgi.machId = conn->getMachId();
     #ifdef FORCEDSHOE 
		sgi.pid         = conn->GetPID();
		sgi.shueMinSize = VP_SHUE_MIN_SIZE;
    #endif

	shue = guts->newShue(sgi);

	if (shue)
		shue->shuffle();
	hand = new VPHand(guts->getCardMgr());
	state = VPGS_NOTSTARTED;
	dblUpPayout = 0;
	dblUpPayType = 0xff;
	dblUpRound = 0;
	dblUpWon = 0;
	restoreLastHeld = 0;			//    info to help restore the client

	cSavHands = (pVPHand*)0;
	nSavHands = 0;
}

VPGame::VPGame(VPConnection* conn, VPokerSavedGame* saved)
{
	this->conn = conn;
	dlbUpCapAmount = conn->getDoubleUpCapAmount();

	// everything else is restored in restore()
	//
	bet = 0;
	shue = (Shue*)0;
	guts = (VPGuts*)0;
	hand = (VPHand*)0;

	cSavHands = (pVPHand*)0;
	nSavHands = 0;

	state = VPGS_GAMEOVER;
	dblUpEnabled = false;
	dblUpPayout = 0;
	dblUpPayType = 0xff;
	dblUpRound = 0;
	dblUpWon = 0;
	restoreLastHeld = 0;			//    info to help restore the client

	if (!restore(saved))
	{
		if( shue ) delete shue;
		if( hand ) delete hand;
		shue = (Shue*)0;
		hand = (VPHand*)0;
		guts = (VPGuts*)0;
		state = VPGS_GAMEOVER;

		delDrawnHands();

	}
}

VPGame::~VPGame()
{
	if( shue )	delete shue;
	if( hand ) 	delete hand;
	guts = (VPGuts*)0;
	shue = (Shue*)0;
	hand = (VPHand*)0;

	delDrawnHands();
}

bool8
VPGame::initOk()
{
	if (state == VPGS_NOTSTARTED ||
		state == VPGS_GAMESTARTED ||
		state == (VPGS_GAMESTARTED | VPGS_DBLUPSTARTED))
		return (bool8)(
			guts != (VPGuts*)0 &&
			shue != (Shue*)0 &&
			hand != (pVPHand)0);
	else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPPENDING))
		return (bool8)(
			guts != (VPGuts*)0 &&
			shue == (Shue*)0 &&
			cSavHands);
	else
		return false;
}

int32
VPGame::getPayFreq()
{
	return guts->getPayFreq();
}

int32
VPGame::deal()
{
	int32 result = DEAL_CREATE_GAME_FAILURE;

	if (state == VPGS_NOTSTARTED)
	{
		// Start the game here validating everything that doesn't require
		// SQL data.  Attempt to create and save the game state in SQL (create
		// the game and save the dealt hands, create a save game, adjust
		// the balance) and validate the rest there. 
		//
		// Any failure will rollback all changes (both in SQL and within the
		// game).
		// 
		if (bet > 0 && bet <= conn->getMaxBet())
		{
			int32			paytype, balance;
			VPHand			clientVisibleHand(guts->getCardMgr());
			VPokerSavedGame	savedGame;

			guts->dealHand(shue, hand);

			//patrick 06/28/02: added sub game member to create game specific information to the client
			guts->createSubGameData(conn->getSubGameData(), conn->getSubGameLengthByRef(), VPConnection::MAX_SUBGAME_DATA);
			
			guts->CalcPayout(&paytype, hand, bet, VPGuts::DEALT_CARDS, conn->getSubGameData(), conn->getSubGameLength());

			guts->makeDealtHandForClient(hand, &clientVisibleHand);

			save(&savedGame);

			result = conn->trackNewGame(
				conn->creditsToCents(bet),
				&clientVisibleHand,
				&savedGame,
				&balance);

			conn->trackNewSubGame();

			if (result == VPConnection::TNG_OK)
			{
				state = VPGS_GAMESTARTED;

				conn->msgStart();
				conn->msgAdd((uint8)'D');
				conn->msgReleaseBuf(clientVisibleHand.out(conn->msgGetBuf()));
				conn->msgAdd(balance);
				conn->msgAdd((uint8)(paytype & 0xFF));
				conn->msgEnd();

				uint8* subdata = conn->getSubGameData();
				int32 length = conn->getSubGameLength();
				if (length > 0)
				{
					conn->msgStart();	//subgame data
					conn->msgAdd((uint8)'S');
					for(int32 i=0;i<length;i++)
					{
						conn->msgAdd(subdata[i]);
					}
					conn->msgEnd();
				}

				result = DEAL_SUCCESS;
			}
			else
			{
				switch (result)
				{
					case VPConnection::TNG_NOMONEY:
						result = DEAL_NOT_ENOUGH_MONEY;
						break;

					default:
						result = DEAL_CREATE_GAME_FAILURE;
						break;
				}

				// roll back server (SQL has already been rolled back)
				//
				guts->rollbackDeal(shue, hand);
			}
		}
		else
			result = DEAL_INVALID_BET;
	}

	return result;
}

int32
VPGame::holdThese(uint8 Cards, uint8 hands)
{
	int32 result = HOLD_FAILURE;

	if (state == VPGS_GAMESTARTED)
	{
		// Continue the game here validating everything that doesn't require
		// SQL data.  Attempt to update the game state in SQL (save drawn
		// hands, remove the saved game, adjust the balance) and validate the
		// rest there. 
		//
		// Any failure will rollback all changes (both in SQL and within the
		// game).
		// 
		if (guts->isHoldTheseValid(Cards))
		{
			uint8 nhand;
			int32	payout, balance;

			pVPHand *clientVisibleHands = new pVPHand[ hands ];

			payout = 0;
			ShueSave seed;		// get seed for theoriginal delt hand
			shue->save( &seed );

			// create temporary shue to draw hands (except the main one)
			Shue *myShue = guts->newShue(sgi);

			// we need to save the dealt hand because the drawn hands
			// MAY not contain any cards from the drawn hand
			uint8 dealtCards[5];
			memcpy(dealtCards, hand->getCards(), 5); 


			for( nhand=0; nhand<hands; nhand++ )
			{
				clientVisibleHands[nhand] = new VPHand( guts->getCardMgr() );

				if( !nhand )
					guts->drawHand(Cards, shue, hand);
				else
				{
					++(seed.seed);
					myShue->restore( &seed );
					if (!guts->drawHandCheck(dealtCards, Cards, myShue, hand))
					{
						delete myShue;
			
						for (int i = 0; i <= nhand; i++)
							delete clientVisibleHands[i];

						delete [] clientVisibleHands;

						return result;
					}
				}

				int32 handPayout = guts->CalcPayout(&paytypes[nhand], hand, bet, VPGuts::DRAWN_CARDS, conn->getSubGameData(), conn->getSubGameLength());
				payout += handPayout;
				guts->makeDrawnHandForClient(hand,clientVisibleHands[nhand] );	

				// save drawn hand
				if( ! conn->trackDrawHand(nhand, clientVisibleHands[nhand],
							conn->creditsToCents(handPayout), paytypes[nhand] ) )
				{
					// roll back server 
					conn->trackDrawHandRollBack();

					guts->rollbackDraw(Cards, shue, hand);
					state &= ~VPGS_DBLUPPENDING;

					ASSERT(state == VPGS_GAMESTARTED);

					delete myShue;
			
					for( int i=0; i<=nhand; i++ )
						delete clientVisibleHands[i];

					delete [] clientVisibleHands;

					return result;
		
				}
			}
			
			dblUpPayout = payout;
			dblUpRound = 0;
			dblUpWon = 0;
			
			//psharpless 10/23/06
			//Case: 11052  New Double Up Win Cap Logic
            if (payout && dblUpEnabled && 
				conn->creditsToCents(payout) <= dlbUpCapAmount)
			{
                state |= VPGS_DBLUPPENDING;
			}

			if (conn->trackDrawDone( conn->creditsToCents(payout),
					(bool8)((state & VPGS_DBLUPPENDING) != 0),	&balance))
			{
				delete shue;
				delete hand;
				shue = (Shue*)0;
				hand = (VPHand*)0;

				if ((state & VPGS_DBLUPPENDING) == 0)
					state = VPGS_GAMEOVER;

				conn->msgStart();
				conn->msgAdd((uint8)'H');
			
				for( nhand=0; nhand<hands; nhand++ )
				{
					conn->msgReleaseBuf(clientVisibleHands[nhand]->out(conn->msgGetBuf()));
					conn->msgAdd((uint8)(paytypes[nhand] & 0xFF));
				}

				conn->msgAdd(payout);
				conn->msgAdd((uint8)((state & VPGS_DBLUPPENDING) != 0));
				conn->msgAdd((uint8)(dblUpPayType & 0xFF));
				conn->msgAdd((uint8)(dblUpWon & 0xFF));
				conn->msgAdd(dblUpPayout);
				conn->msgAdd(balance);
				conn->msgEnd();

				result = (state == VPGS_GAMEOVER
					? HOLD_SUCCESS_GAMEOVER
					: HOLD_SUCCESS_DBLUP_PENDING);
			}
			else
			{
				// roll back server (SQL has already been rolled back)
				//
				conn->trackDrawHandRollBack();
				guts->rollbackDraw(Cards, shue, hand);
				state &= ~VPGS_DBLUPPENDING;

				ASSERT(state == VPGS_GAMESTARTED);
			}
			
			delete myShue;
			
			for( nhand=0; nhand<hands; nhand++ )
				delete clientVisibleHands[nhand];

			delete [] clientVisibleHands;
				
		}
	}

	return result;
}

bool8
VPGame::doubleUpDeny()
{
	bool8 result = false;

	if (state & VPGS_DBLUPPENDING)
	{
		int32 balance;

		if (conn->trackDoubleUpDeny(
			conn->creditsToCents(dblUpPayout),
			&balance))
		{
			state = VPGS_GAMEOVER;

			conn->msgStart();
			conn->msgAdd((uint8)'X');
			conn->msgAdd((uint8)(dblUpPayType & 0xFF));
			conn->msgAdd(dblUpPayout);
			conn->msgAdd(balance);
			conn->msgEnd();

			result = true;
		}
		//
		// upon failure, everything already rolled-back
		//
	}

	return result;
}

bool8
VPGame::doubleUpDeal()
{
	bool8 result = false;

	if (state & VPGS_DBLUPPENDING)
	{
		shue = guts->newShue(sgi);
		hand = new VPHand(guts->getCardMgr());

		if (shue && hand)
		{
			ShueSave shueSave;
			int32 balance;

			shue->shuffle();
			hand->add(shue->getCard());

			shue->save(&shueSave);

			if (conn->trackDoubleUpDeal(
				dblUpRound,
				hand->getCardAt(0),
				&shueSave,
				&balance))
			{
				state &= ~VPGS_DBLUPPENDING;
				state |= VPGS_DBLUPSTARTED;

				conn->msgStart();
				conn->msgAdd((uint8)'U');
				conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
				conn->msgAdd(balance);
				conn->msgEnd();

				result = true;
			}
		}

		//
		// upon failure, rollback
		//
		if (!result)
		{
			delete shue;
			delete hand;
			shue = (Shue*)0;
			hand = (VPHand*)0;
		}
	}

	return result;
}

int32
VPGame::doubleUpDraw(uint8 held)
{
	int32 result = DUDRAW_FAILURE;

	if ((state & VPGS_DBLUPSTARTED) != 0 && held >= 1 && held < 5)
	{
		int32 newDblUpPayout, newDblUpPayType, newDblUpRound, newDblUpWon;
		int32 winner;
		int32 newState;
		int32 balance;

		hand->add(shue->getCard());
		hand->add(shue->getCard());
		hand->add(shue->getCard());
		hand->add(shue->getCard());

		winner = guts->doubleUpCompare(
			hand->getCardAt(0),
			hand->getCardAt(held));

		if (winner > 0)
		{
			newDblUpPayout = 0;						// house wins
			newDblUpPayType = VPEVT_DBLUP_LOSER;
			newDblUpRound = 0;
			newDblUpWon = 0;
			newState = VPGS_GAMEOVER;
		}
		else if (winner < 0)
		{
			newDblUpPayout = dblUpPayout << 1;		// player wins
			newDblUpPayType = VPEVT_DBLUP_WON;
			newDblUpRound = dblUpRound + 1;
			newDblUpWon = dblUpWon + 1;
            newState = state & ~VPGS_DBLUPSTARTED;

			//psharpless 10/23/06
			//Case: 11052  New Double Up Win Cap Logic
			if(conn->creditsToCents(newDblUpPayout) <= dlbUpCapAmount)
			{
				newState = newState | VPGS_DBLUPPENDING;
			}
		}
		else
		{
			newDblUpPayout = dblUpPayout;			// tie
			newDblUpPayType = VPEVT_DBLUP_TIE;
			newDblUpRound = dblUpRound + 1;
			newDblUpWon = dblUpWon;
			newState = (state & ~VPGS_DBLUPSTARTED) | VPGS_DBLUPPENDING;
		}

		if (conn->trackDoubleUpDraw(dblUpRound,
			hand->getCardAt(held),
			winner,
			conn->creditsToCents(newDblUpPayout),
			&balance))
		{
			dblUpPayout = newDblUpPayout;
			dblUpPayType = newDblUpPayType;
			dblUpRound = newDblUpRound;
			dblUpWon = newDblUpWon;
			state = newState;

			conn->msgStart();
			conn->msgAdd((uint8)'u');
			conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));
			conn->msgAdd((uint8)((state & VPGS_DBLUPPENDING) != 0));
			conn->msgAdd((uint8)(dblUpPayType));
			conn->msgAdd((uint8)(dblUpWon & 0xFF));
			conn->msgAdd(dblUpPayout);
			conn->msgAdd(balance);
			conn->msgEnd();

			delete shue;
			delete hand;
			shue = (Shue*)0;
			hand = (VPHand*)0;

			//psharpless 10/23/06
			//Case: 11052  New Double Up Win Cap Logic

			//we just won a double up, but another double up is not pending, 
			//we must have hit the cap so update the users balance with their winnings
			if(dblUpWon && !(state & VPGS_DBLUPPENDING))
			{
				conn->trackDoubleUpDeny(conn->creditsToCents(dblUpPayout),&balance);
			}

			result = (state & VPGS_DBLUPPENDING
				? DUDRAW_SUCCESS_DBLUP_PENDING
				: DUDRAW_SUCCESS_GAMEOVER);
		}
		else
		{
			// roll back server (SQL has already been rolled back)
			//
			shue->pushBackNCards(4);
			hand->removeAt(4);
			hand->removeAt(3);
			hand->removeAt(2);
			hand->removeAt(1);
		}
	}

	return result;
}

void 
VPGame::save(VPokerSavedGame* saved)
{
	shue->save(&saved->shue);
	saved->bet = conn->creditsToCents(bet);
	saved->payFreq = guts->getPayFreq();
	saved->dblUpEnabled = dblUpEnabled;
	//
	// the rest is already stored in the database
	//
}

bool8 
VPGame::restore(VPokerSavedGame* saved)
{
	bool8 result = false;

	sgi.gameId = GAMEID;
	sgi.machId = conn->getMachId();
#ifdef FORCEDSHOE
	sgi.pid         = conn->GetPID();
	sgi.shueMinSize = VP_SHUE_MIN_SIZE;
#endif

	switch (saved->kind)
	{
		case VPokerSavedGame::VPOKER_PLAYING:
			guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
			if (guts)
			{
				shue = guts->newShue(sgi);
				if (shue)
				{
					shue->restore(&saved->shue);

					hand = new VPHand(guts->getCardMgr());
					if (hand)
					{
						guts->restoreHand(shue, hand, saved);
						bet = conn->centsToCredits(saved->bet);
						dblUpEnabled = saved->dblUpEnabled;

						state = VPGS_GAMESTARTED;

						result = true;
					}
				}
			}
			break;

		case VPokerSavedGame::DBLUP_AVAIL_1ST:
			guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);

			if (guts)
			{
				ASSERT(shue == (Shue*)0);

				// cSavHands hold the results of the final vpoker game;
				// They are only kept around long enough to send to the client
				// and then they are destroyed in VPGame::send().
				// (it shouldn't exist in the server at this state in the game).
				//

				uint8	drawncards[100][5];
				if( conn->getDrawnCards( drawncards, payouts, paytypes, &nSavHands ) )
				{
					cSavHands = new pVPHand[nSavHands];
					dblUpPayout = 0;

					// restore all drawn hands
					for( int i=0; i<nSavHands; i++ )
					{
						cSavHands[i] = new VPHand(guts->getCardMgr());
						cSavHands[i]->restore(drawncards[i], VPokerSavedGame::MAXCARDS);

						dblUpPayout += conn->centsToCredits(payouts[i]);
					}

					bet = conn->centsToCredits(saved->bet);
					dblUpEnabled = saved->dblUpEnabled;
					
					// this equality is sign that DBLUP is available first time (for client)
					dblUpPayType = paytypes[0];

					restoreLastHeld = guts->restoreHeldCards(
						saved->dblUpLastDealt, drawncards[0],
						VPokerSavedGame::MAXCARDS);
								
					state = VPGS_GAMESTARTED | VPGS_DBLUPPENDING;
					result = true;
				}

			}
			break;

		case VPokerSavedGame::DBLUP_AVAIL_NOT1ST:
			guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
			if (guts)
			{

				shue = guts->newShue(sgi);
				if (shue)
				{
					shue->restore(&saved->shue);


					uint8	drawncards[100][5];
					if( conn->getDrawnCards( drawncards, payouts, paytypes, &nSavHands ) )
					{
						int32 i;
						cSavHands = new pVPHand[nSavHands];

						// restore dblUp cards first

						cSavHands[0] = new VPHand(guts->getCardMgr());
						cSavHands[0]->add(shue->getCard());
						cSavHands[0]->add(shue->getCard());
						cSavHands[0]->add(shue->getCard());
						cSavHands[0]->add(shue->getCard());
						cSavHands[0]->add(shue->getCard());

						// restore "small" drawn hands
						for( i=1; i<nSavHands; i++ )
						{
							cSavHands[i] = new VPHand(guts->getCardMgr());
							cSavHands[i]->restore(drawncards[i], VPokerSavedGame::MAXCARDS);
						}

///////////

						delete shue;
						shue = (Shue*)0;

						ASSERT(cSavHands[0]->getCardAt(0) == saved->cards[0]);

						restoreLastHeld = 0;
						for (i = 1; i < 5; i++)
						{
							if (cSavHands[0]->getCardAt(i) == saved->cards[1])
							{
								restoreLastHeld = (uint8)(i & 0xFF);
								break;
							}
						}

						ASSERT(restoreLastHeld > 0 &&
							restoreLastHeld < 5 &&
							(saved->dblUpLastOutcome == 'W' ||
								saved->dblUpLastOutcome == 'T'));

						bet = conn->centsToCredits(saved->bet);
						dblUpEnabled = saved->dblUpEnabled;
						dblUpPayout = conn->centsToCredits(saved->dblUpPayout);
						dblUpPayType =
							saved->dblUpLastOutcome == 'W'
								? VPEVT_DBLUP_WON
								: VPEVT_DBLUP_TIE;
						dblUpRound = saved->dblUpRound;
						dblUpWon = saved->dblUpWins;

						state = VPGS_GAMESTARTED | VPGS_DBLUPPENDING;

						result = true;
					}
				}


			}
			break;

		case VPokerSavedGame::DBLUP_PLAYING:

			guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
			if (guts)
			{
				uint8	drawncards[100][5];
				if( conn->getDrawnCards( drawncards, payouts, paytypes, &nSavHands ) )
				{
					cSavHands = new pVPHand[nSavHands];

					// restore all drawn hands
					for( int i=0; i<nSavHands; i++ )
					{
						cSavHands[i] = new VPHand(guts->getCardMgr());
						cSavHands[i]->restore(drawncards[i], VPokerSavedGame::MAXCARDS);
					}

//////////

					shue = guts->newShue(sgi);
					if (shue)
					{
						shue->restore(&saved->shue);

						hand = new VPHand(guts->getCardMgr());
						if (hand)
						{
							hand->add(shue->getCard());

							ASSERT(hand->getCardAt(0) == saved->cards[0]);

							if (saved->dblUpRound == 0)
								dblUpPayType = saved->dblUpOrigPayType;
							else
							{
								ASSERT(saved->dblUpLastOutcome == 'W' ||
									saved->dblUpLastOutcome == 'T');

								dblUpPayType =
									saved->dblUpLastOutcome == 'W'
										? VPEVT_DBLUP_WON
										: VPEVT_DBLUP_TIE;
							}

							bet = conn->centsToCredits(saved->bet);
							dblUpEnabled = saved->dblUpEnabled;
							dblUpPayout = conn->centsToCredits(saved->dblUpPayout);
							dblUpRound = saved->dblUpRound;
							dblUpWon = saved->dblUpWins;

							state = VPGS_GAMESTARTED | VPGS_DBLUPSTARTED;

							result = true;
						}
					}
				}
			}
			break;

		default:
			break;
	}
	//
	// At this point the server is *exactly* the same as when the game was
	// saved:  all automatic playing had already completed and the game
	// was idle.
	//
	conn->trackGetSubGame();
	guts = VPGuts::getGuts(conn->getMachId(), saved->payFreq);
	guts->restoreSubGameData(conn->getSubGameData(), conn->getSubGameLengthByRef());

	return result;
}

void 
VPGame::send()
{
	//
	// This message is contained within another message
	// (don't call msgStart()/msgEnd()).
	//
	if (state == VPGS_GAMESTARTED)
	{
		VPHand	clientVisibleHand(guts->getCardMgr());
		int32	paytype;

		guts->CalcPayout(&paytype, hand, bet, VPGuts::DEALT_CARDS, conn->getSubGameData(), conn->getSubGameLength());
		guts->makeDealtHandForClient(hand, &clientVisibleHand);

		conn->msgAdd((uint8)0x00);	// restore vpoker game
		conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
		conn->msgAdd(bet);
		conn->msgAdd((uint8)(paytype & 0xFF));
		conn->msgReleaseBuf(clientVisibleHand.out(conn->msgGetBuf()));
	}
	else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPPENDING))
	{
		conn->msgAdd((uint8)0x01);	// restore dblup pending
		conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
		conn->msgAdd(bet);
		conn->msgAdd((uint8)(restoreLastHeld & 0xFF));
		conn->msgAdd(dblUpPayout);
		conn->msgAdd((uint8)(dblUpPayType & 0xFF));
		conn->msgAdd((uint8)(dblUpWon & 0xFF));

		// send all drawn hands & paytypes
		for( int i=0; i<nSavHands; i++ )
		{
			conn->msgReleaseBuf(cSavHands[i]->out(conn->msgGetBuf()));
			conn->msgAdd((uint8)(paytypes[i] & 0xFF));
		}

		delDrawnHands();	// as promised :)

		restoreLastHeld = 0;
	}

	else if (state == (VPGS_GAMESTARTED | VPGS_DBLUPSTARTED))
	{
		conn->msgAdd((uint8)0x02);	// restore dblup started
		conn->msgAdd((uint8)(guts->getPayFreq() & 0xFFL));
		conn->msgAdd(bet);
		conn->msgAdd((uint8)(dblUpPayType & 0xFF));
		conn->msgAdd((uint8)(paytypes[0] & 0xFF));
		conn->msgAdd((uint8)(dblUpWon & 0xFF));
		conn->msgAdd(dblUpPayout);
		conn->msgReleaseBuf(hand->out(conn->msgGetBuf()));

		// send all "small" drawn hands & paytypes
		for( int i=1; i<nSavHands; i++ )
		{
			conn->msgReleaseBuf(cSavHands[i]->out(conn->msgGetBuf()));
			conn->msgAdd((uint8)(paytypes[i] & 0xFF));
		}

		delDrawnHands();	// as promised :)
		
	}
	else
		ASSERT(0);
}

void
VPGame::delDrawnHands()
{
	if( cSavHands )
	{
		for( int i=0; i<nSavHands; i++ )
			delete cSavHands[i];
		delete [] cSavHands;
	}
		
	cSavHands = (pVPHand*)0;
	nSavHands = 0;

}